﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Paddings;
using Org.BouncyCastle.Crypto.Parameters;

namespace LockCrypt.Core {
    public class Aes256EncryptionService : EncryptionBase {
        private byte[] _key;

        /// <summary>
        /// Gets the encryption type.
        /// </summary>
        /// <value>The encryption type.</value>
        public override EncryptionProviders EncryptionAlgorithm {
            get { return EncryptionProviders.Aes256; }
        }

        /// <summary>
        /// Gets or sets the encryption key.
        /// </summary>
        /// <value>The encryption key.</value>
        public override string EncryptionKey {
            get { return _key == null ? null : Encoding.UTF8.GetString(_key); }
            set {
                _key = GetKeyBytes(value);
            }
        }

        public Aes256EncryptionService()
            :base() {
            EncryptionKey = string.Empty;
            this.PaddingMode = PaddingMode.Zeros;
        }
        public Aes256EncryptionService(string key)
            : base() {
            EncryptionKey = key;
        }

        /// <summary>
        /// Gets the equivalent key for a password, as a string.
        /// </summary>
        /// <param name="password">The password.</param>
        /// <returns>The string equivalent of the encryption key which would be used for the password.</returns>
        public override string GetKey(string password) {
            return password == null ? null : Encoding.UTF8.GetString(GetKeyBytes(password));
        }

        /// <summary>
        /// Gets the equivalent key for a password.
        /// </summary>
        /// <param name="password">The password.</param>
        /// <returns>The encryption key which would be used for the password.</returns>
        public override byte[] GetKeyBytes(string password) {
            byte[] key = Encoding.UTF8.GetBytes(password ?? string.Empty);
            if(key.Length != 128 && key.Length != 192 && key.Length != 256) {
                Array.Resize(ref key, 16);
            }
            return key;
        }

        public override byte[] Encrypt(byte[] input) {
            //return input;
            ICipherParameters cipherParameters = new KeyParameter(_key);
            // A full list of BlockCiphers can be found at http://www.bouncycastle.org/docs/docs1.6/org/bouncycastle/crypto/BlockCipher.html
            IBlockCipher blockCipher = new AesEngine();
            IBlockCipherPadding blockCipherPadding = base.GetPadding();
            BufferedBlockCipher bufferedBlockCipher = new PaddedBufferedBlockCipher(blockCipher, blockCipherPadding);
            return Encrypt(input, bufferedBlockCipher, cipherParameters);
        }

        public override byte[] Decrypt(byte[] input) {
            //return input;
            ICipherParameters cipherParameters = new KeyParameter(_key);
            IBlockCipher blockCipher = new AesEngine();
            IBlockCipherPadding blockCipherPadding = base.GetPadding();
            BufferedBlockCipher bufferedBlockCipher = new PaddedBufferedBlockCipher(blockCipher, blockCipherPadding);

            return Decrypt(input, bufferedBlockCipher, cipherParameters);
        }
    }
}
